package cn.enjoy.socket.websocket;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author K
 * @date 2024-06-04 21:07
 * 注：WebSocket是多例对象，每次一个用户请求都会创建一个新的WebSocket供本次操作
 * WebSocket文件
 **/
@Slf4j
@Component
@ServerEndpoint("/chatRoom/{username}")
public class ChatRoom {

    //当前客户端连接数
    private static Integer onlineCount = 0;
    //用来记录处于活跃的Socket连接
    private static Map<String, ChatRoom> clients = new ConcurrentHashMap<String, ChatRoom>();
    //用来记录当前连接登录的Session
    private Session session;
    //用来记录当前登录人信息
    private String userMessage;

    /***
     * 创建连接时触发（有客户端请求时打印）
     * @param username 代表地址参数中的{name}信息，用于接收URL传递的参数（这里代表是谁提交的信息）
     * @param session 当前建立的连接
     */
    @OnOpen
    public void onOpen(@PathParam("username") String username, Session session) {
        log.info("{}触发 >>> 创建连接触发onOpen()方法设置信息！并设置记录信息", username);
        this.session = session;
        this.userMessage = username;
        clients.put(username, this);    // 当前Socket存起来
        addOnlineCount();               // 当前连接数加1
    }

    /***
     * 接收到信息时触发；用于接收客户端发送来的消息，（具体按照业务编写内部代码）
     * 如两个人聊天：应该是看接收到的消息解析后，看看具体发送给谁的，然后转发给另外一个人
     * 比如传来的message可以是如下格式：{"to":"jack","message","您好"}；这时解析后就知道是发送给jack
     * 这时我只需要在 “clients” 集合里找到具体的人转发即可
     * @param session 当前用户连接的Session对象
     * @param message 当前用户发送来的消息（一般为Json数据，好解析）
     */
    @OnMessage
    public void onMessage(Session session, String message) {
        log.info("{}触发 >>> 接收到信息触发onMessage()方法，处理信息！并返回结果", this.userMessage);
        //解析Json（并获取消息和消息发给谁）
        JSONObject jsonObject = JSONObject.parseObject(message);
        String msgData = jsonObject.getString("toMessage");
        String toName = jsonObject.getString("toName");

        //根据信息名称去集合查询用户信息
        ChatRoom webSocket = getClients().get(toName);
        //判断当前的WebSocket是否存在0
        if (webSocket != null) {
            //获取在集合中查询到的Session用户信息，并进行远程调用
            RemoteEndpoint.Async asyncRemote = webSocket.getSession().getAsyncRemote();
            //拼接数据
            String str = "【" + this.userMessage + "】在[" +
                    new SimpleDateFormat("HH:mm:ss").format(new Date()) + "]:" + msgData;
            asyncRemote.sendText(str);
        } else {
            session.getAsyncRemote().sendText("当前用户不在线，请稍后联系....");
        }
    }

    /***
     * 通讯异常时触发
     * @param session 当前用户连接的Session对象
     * @param e 异常信息
     */
    @OnError
    public void onError(Session session, Throwable e) {
        log.info("{}触发 >>> 通讯异常触发onError()方法，异常信息为：{}", this.userMessage, e.getMessage());
    }

    /***
     * 连接断开时触发
     * @param session 当前用户连接的Session对象
     */
    @OnClose
    public void onClose(Session session) {
        log.info("{}触发 >>> 连接断开触发onClose()方法，结束连接，关闭：{} 的连接", this.userMessage, this.userMessage);
        clients.remove(this.userMessage);
        subOnlineCount();
    }

    /***
     * 获取当前客户端连接数
     * @return Integer
     */
    public static synchronized Integer getOnlineCount() {
        return onlineCount;
    }

    /***
     * 当前客户端连接数+1
     */
    public static synchronized void addOnlineCount() {
        ChatRoom.onlineCount++;
    }

    /***
     * 当前客户端连接数-1
     */
    public static synchronized void subOnlineCount() {
        ChatRoom.onlineCount--;
    }

    /***
     * 获取session信息
     * @return Session
     */
    public Session getSession() {
        return session;
    }

    /***
     * 获取当前全部活跃的连接
     * @return 活跃集合
     */
    public static synchronized Map<String, ChatRoom> getClients() {
        return clients;
    }
}